#include "StdAfx.h"
#include "HttpUtility.h"

namespace HttpUtility
{
	int GetHttpHeaderLength(const char* p, int n)
	{
		if (n)
		{
			char c = p[n];
			((char*)p)[n] = '\0';
			char* q = strstr((char*)p, "\r\n\r\n");
			((char*)p)[n] = c;
			if (q)
			{
				int m = q - p + 4;
				return m;
			}
		}
		return 0;
	}

	bool GetHttpHeader(const char* header, int headerlen, const char* name, const char*& value, int& len)
	{
		char c = header[headerlen];
		((char*)header)[headerlen] = '\0';
		char name_x[1024];
		sprintf_s(name_x, sizeof(name_x), "\r\n%s:", name);
		char* p = strstr((char*)header, name_x);
		if (!p)
		{
			for (char* t = p; t; ++t)
				*t = tolower(*t);
			p = strstr((char*)header, name_x);
		}
		if (!p)
		{
			((char*)header)[headerlen] = c;
			return false;
		}
		p += strlen(name_x);
 		while (*p > '\0' && *p <= ' ')
			++p;
		value = p;
		len = strstr(p, "\r\n") - p;
		((char*)header)[headerlen] = c;
		return true;
	}

	CString GetHttpRequestURL(const char* p, int n, u_long addr, u_short port)
	{
		char url[1024] = "http://";
		int len = 7;
		const char* value;
		int valuelen;
		if (GetHttpHeader(p, n, "Host", value, valuelen))
		{
			memcpy(url + len, value, valuelen);
			len += valuelen;
		}
		else
		{
			sprintf_s(url + len, sizeof(url) - len, "%u.%u.%u.%u", addr >> 24, (addr >> 16) & 0xFF, (addr >> 8) & 0xFF, addr & 0xFF);
			len += strlen(url + len);
		}
		if (port != 80)
		{
			sprintf_s(url + len, sizeof(url) - len, ":%u", port);
			len += strlen(url + len);
		}
		const char* q = strchr(p, ' ');
		ASSERT(q);
		++q;
		const char* r = strchr(q, ' ');
		ASSERT(r);
		int l = r - q;
		memcpy(url + len, q, l);
		len += l;
		url[len] = '\0';
		return (CString)url;
	}

	int GetHttpRequestLength(const char* p, int n, int header)
	{
		const char* value;
		int valuelen;
		int l = header + (GetHttpHeader(p, header, "Content-Length", value, valuelen) ? atoi(value) : 0);
		if (n >= l)
			return l;
		return 0;
	}

	int GetHttpResponseStatusCode(const char* header)
	{
		return atoi(header + 9);
	}

	int GetHttpResponseChunkedLength(const char* p, int n, int& cl)
	{
		char* p0 = (char*)p;
		char* e = p0 + n;
		char c = *e;
		*e = '\0';
		cl = 0;
		for ( ; ; )
		{
			char* q = strstr((char*)p, "\r\n");
			if (!q || q - p > 10)
				break;
			char ls[16] = "0x";
			memcpy(ls + 2, p, q - p);
			ls[2 + (q - p)] = '\0';
			int l = (int)strtol(ls, NULL, 16);
			cl += l;
			const char* p1 = p;
			p = q + 2 + l + 2;
			n -= (p - p1);
			if (n < 0)
				break;
			if (l == 0)
			{
				*e = c;
				return p - p0;
			}
		}
		*e = c;
		return 0;
	}

	int GetHttpResponseLength(const char* p, int n, int header, bool closed, bool& chunked, int& cl)
	{
		const char* value;
		int valuelen;
		if (closed)
		{
			cl = n - header;
			return n;
		}
		else if (chunked || GetHttpHeader(p, header, "Transfer-Encoding", value, valuelen) && _strnicmp("chunked", value, valuelen) == 0)
		{
			chunked = true;
			int l = GetHttpResponseChunkedLength(p + header, n - header, cl);
			if (l)
				return header + l;
		}
		else if (GetHttpHeader(p, header, "Content-Length", value, valuelen))
		{
			cl = atoi(value);
			if (n >= header + cl)
				return header + cl;
		}
		return 0;
	}

	int GetHttpResponseChunkedData(u_char* data, int size, const char* p)
	{
		int total = 0;
		for ( ; ; )
		{
			char* q = strstr((char*)p, "\r\n");
			ASSERT(q);
			char ls[16] = "0x";
			memcpy(ls + 2, p, q - p);
			ls[2 + (q - p)] = '\0';
			int l = (int)strtol(ls, NULL, 16);
			if (!l)
				break;
			p = q + 2;
			l = min(l, size);
			memcpy(data, p, l);
			total += l;
			size -= l;
			if (size <= 0)
				break;
			data += l;
			p += l + 2;
		}
		return total;
	}

	int GetHttpResponseData(u_char* data, int size, const char* p, int n, int header, bool chunked)
	{
		if (chunked)
			return GetHttpResponseChunkedData(data, size, p + header);
		size = min(size, n - header);
		memcpy(data, p + header, size);
		return size;
	}

	int gzipDecode(Byte *zdata, uLong nzdata, Byte *data, uLong ndata)
	{
		int err = 0;
		z_stream d_stream = {0}; /* decompression stream */
		static char dummy_head[2] = {
			0x8 + 0x7 * 0x10,
			(((0x8 + 0x7 * 0x10) * 0x100 + 30) / 31 * 31) & 0xFF,
		};
		d_stream.zalloc = NULL;
		d_stream.zfree = NULL;
		d_stream.opaque = NULL;
		d_stream.next_in  = zdata;
		d_stream.avail_in = 0;
		d_stream.next_out = data;
		if (inflateInit2(&d_stream, MAX_WBITS + 16) != Z_OK)
			return 0;
		while (d_stream.total_in < nzdata)
		{
			d_stream.avail_in = d_stream.avail_out = 1; /* force small buffers */
			if ((err = inflate(&d_stream, Z_NO_FLUSH)) == Z_STREAM_END)
			{
				if (inflateEnd(&d_stream) != Z_OK)
					return 0;
				break;
			}
			if (err != Z_OK)
			{
				if (err == Z_DATA_ERROR)
				{
					d_stream.next_in = (Bytef*) dummy_head;
					d_stream.avail_in = sizeof(dummy_head);
					if ((err = inflate(&d_stream, Z_NO_FLUSH)) != Z_OK)
						return 0;
				}
				else
					return 0;
			}
			if (d_stream.total_out >= ndata)
				break;
		}
		return d_stream.total_out;
	}
}
